package com.sz.mes.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.diboot.core.binding.Binder;
import com.diboot.core.util.BeanUtils;
import com.diboot.core.util.D;
import com.diboot.core.util.V;
import com.diboot.file.util.ExcelHelper;
import com.diboot.iam.dto.IamUserSearchDTO;
import com.diboot.iam.entity.IamUser;
import com.diboot.iam.vo.IamUserVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sz.mes.dto.TechniqueDTO;
import com.sz.mes.entity.*;
import com.sz.mes.excel.model.IamUserExportModel;
import com.sz.mes.excel.model.ProductTaskExportModel;
import com.sz.mes.mapper.CompleteRptMapper;
import com.sz.mes.mapper.ProductTaskMapper;
import com.sz.mes.mapper.TechMapper;
import com.sz.mes.mapper.TechniqueMapper;
import com.sz.mes.service.TechniqueService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.diboot.core.vo.*;
import com.diboot.iam.annotation.OperationCons;
import com.diboot.iam.annotation.BindPermission;
import com.diboot.iam.annotation.Log;
import com.sz.mes.dto.ProductTaskDTO;
import com.sz.mes.vo.ProductTaskListVO;
import com.sz.mes.vo.ProductTaskDetailVO;
import com.sz.mes.service.ProductTaskService;
import com.sz.mes.controller.BaseCustomCrudRestController;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.diboot.file.service.UploadFileService;

/**
 * 生产任务 相关Controller
 *
 * @author hem
 * @version 1.0
 * @date 2023-05-19
 * Copyright © szhs
 */
@RestController
@RequestMapping("/productTask")
@BindPermission(name = "生产任务")
@Slf4j
public class ProductTaskController extends BaseCustomCrudRestController<ProductTask> {

    @Autowired
    private ProductTaskService productTaskService;

    @Autowired
    private UploadFileService uploadFileService;

    @Autowired
    private TechniqueService techniqueService;

    @Autowired
    private ProductTaskMapper productTaskMapper;

    @Autowired
    private TechniqueMapper techniqueMapper;

    @Autowired
    private TechMapper techMapper;

    @Autowired
    private CompleteRptMapper completeRptMapper;

    /**
     * 查询ViewObject的分页数据
     * <p>
     * url请求参数示例: /list?field=abc&pageIndex=1&orderBy=abc:DESC
     * </p>
     *
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @GetMapping("/list")
    public JsonResult getViewObjectListMapping(ProductTaskDTO queryDto, Pagination pagination) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        List<ProductTaskListVO> data = null;
        QueryWrapper<ProductTask> productTaskQueryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(queryDto.getPlanNum())) {
            productTaskQueryWrapper.like("plan_num", queryDto.getPlanNum());
        } else if (!StringUtils.isEmpty(queryDto.getReceiptNum())) {
            productTaskQueryWrapper.like("receipt_num", queryDto.getReceiptNum());
        } else if (!StringUtils.isEmpty(queryDto.getProductNum())) {
            productTaskQueryWrapper.like("product_num", queryDto.getProductNum());
        } else if (!StringUtils.isEmpty(queryDto.getStockNum())) {
            productTaskQueryWrapper.like("stock_num", queryDto.getStockNum());
        } else {
//            data = super.getViewObjectList(queryDto, pagination.setOrderBy("receipt_num:DESC"), ProductTaskListVO.class).getData();
            data = super.getViewObjectList(queryDto, pagination.setOrderBy("id:ASC"), ProductTaskListVO.class).getData();
//            Collections.reverse(data);
            map.put("data", data);
        }
        if (data == null) {
//            List<ProductTask> data1 = super.getEntityListWithPaging(productTaskQueryWrapper, pagination.setOrderBy("receipt_num:DESC")).getData();
            List<ProductTask> data1 = super.getEntityListWithPaging(productTaskQueryWrapper, pagination.setOrderBy("id:ASC")).getData();
//            Collections.reverse(data1);
            data = Binder.convertAndBindRelations(data1, ProductTaskListVO.class);
            map.put("data", data);
        }
        for (ProductTaskListVO datum : data) {
            QueryWrapper<Tech> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("task_num", datum.getTaskNum());
            List<Tech> techList = techMapper.selectList(queryWrapper);
            if (techList.size() > 0) {
                datum.setIsTech(1);
            } else {
                datum.setIsTech(0);
            }
            QueryWrapper<Technique> techniqueQueryWrapper = new QueryWrapper<>();
            techniqueQueryWrapper.eq("task_num", datum.getTaskNum());
            Long aLong = techniqueMapper.selectCount(techniqueQueryWrapper);
            // 工序详情有数据代表任务进行中，反之任务未开始
            if (aLong > 0) {
                datum.setProductTaskStatus(1);
            } else {
                datum.setProductTaskStatus(0);
            }
            // if (techniqueList.size() > 0) {
            // datum.setProductTaskStatus(1);
            // } else {
            // datum.setProductTaskStatus(0);
            // }
            String receiptNum = datum.getReceiptNum();
            String substring = receiptNum.substring(2);
            String completeRptReceiptNum = "WG" + substring;
            QueryWrapper<CompleteRpt> completeRptQueryWrapper = new QueryWrapper<>();
            completeRptQueryWrapper.eq("receipt_num", completeRptReceiptNum);
            List<CompleteRpt> completeRpts = completeRptMapper.selectList(completeRptQueryWrapper);
            // 只要生产完工表有数据的时候，任务才算已完成
            if (completeRpts.size() > 0) {
                datum.setProductTaskStatus(2);
            }
        }
        map.put("page", pagination);
        return JsonResult.OK(map);
    }

    /**
     * 根据资源id查询ViewObject
     *
     * @param id ID
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_DETAIL)
    // @BindPermission(name = OperationCons.LABEL_DETAIL, code = OperationCons.CODE_READ)
    @GetMapping("/{id}")
    public JsonResult getViewObjectMapping(@PathVariable("id") Long id) throws Exception {
        return super.getViewObject(id, ProductTaskDetailVO.class);
    }

    /**
     * 创建资源对象
     *
     * @param entity
     * @return JsonResult
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_CREATE)
    // @BindPermission(name = OperationCons.LABEL_CREATE, code = OperationCons.CODE_WRITE)
    @PostMapping("/")
    public JsonResult createEntityMapping(@Valid @RequestBody ProductTask entity) throws Exception {
        QueryWrapper<ProductTask> productTaskQueryWrapper = new QueryWrapper<>();
        productTaskQueryWrapper.eq("receipt_num", entity.getReceiptNum());
        productTaskQueryWrapper.eq("stock_num", entity.getStockNum());
        ProductTask productTask = productTaskMapper.selectOne(productTaskQueryWrapper);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        // String start = entity.getStartTime();
        // String end = entity.getEndTime();
        Date startTime = entity.getStartTime();
        Date endTime = entity.getEndTime();
        // Date startTime = simpleDateFormat.parse(start);
        // Date endTime = simpleDateFormat.parse(end);
        long startWorkTime = startTime.getTime();
        long finishWorkTime = endTime.getTime();
        // 只有数据库没值的时候才能创建
        if (productTask == null) {
            // 完工日期不能早于开工日期
            if (finishWorkTime < startWorkTime) {
                return JsonResult.FAIL_OPERATION("完工日期不能早于开工日期");
            } else {
                String receiptNum = entity.getReceiptNum();
                String substring = receiptNum.substring(2);
                entity.setTaskNum("RWD"+substring);
                return super.createEntity(entity);
            }
        } else {
            return JsonResult.FAIL_OPERATION("该订单已存在");
        }
    }

    /**
     * 根据ID更新资源对象
     *
     * @param entity
     * @return JsonResult
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_UPDATE)
    // @BindPermission(name = OperationCons.LABEL_UPDATE, code = OperationCons.CODE_WRITE)
    @PutMapping("/{id}")
    public JsonResult updateEntityMapping(@PathVariable("id") Long id, @Valid @RequestBody ProductTask entity) throws Exception {
        QueryWrapper<ProductTask> productTaskQueryWrapper = new QueryWrapper<>();
        productTaskQueryWrapper.eq("receipt_num", entity.getReceiptNum());
        productTaskQueryWrapper.eq("stock_num", entity.getStockNum());
        ProductTask productTask = productTaskMapper.selectOne(productTaskQueryWrapper);
        ProductTask currentProductTask = productTaskMapper.selectById(id);
        if (entity.getReceiptNum().equals(currentProductTask.getReceiptNum()) && entity.getStockNum().equals(currentProductTask.getStockNum())) {
            return super.updateEntity(id, entity);
        } else {
            if (productTask != null) {
                return JsonResult.FAIL_EXCEPTION("该任务单已存在");
            } else {
                return super.updateEntity(id, entity);
            }
        }
    }

    /**
     * 根据id删除资源对象
     *
     * @param id
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_DELETE)
    // @BindPermission(name = OperationCons.LABEL_DELETE, code = OperationCons.CODE_WRITE)
    @DeleteMapping("/{id}")
    public JsonResult deleteEntityMapping(@PathVariable("id") Long id) throws Exception {
        return super.deleteEntity(id);
    }

    /**
     * excel导入
     *
     * @param entity
     * @return JsonResult
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_CREATE)
    // @BindPermission(name = OperationCons.LABEL_CREATE, code = OperationCons.CODE_WRITE)
    @PostMapping("/excel")
    public JsonResult insert(@Valid @RequestBody ProductTask entity) throws Exception {
        List<String> receiptNumAndstockNumList = new ArrayList<>();
        String excelData = entity.getExcelData();
        JSONArray objects = JSONObject.parseArray(excelData);
        for (Object object : objects) {
            HashMap<String, String> hashMap = JSONObject.parseObject(JSONObject.toJSONString(object), HashMap.class);
            String receiptNum = hashMap.get("单据编号");
            String stockNum = hashMap.get("备料料号");
            String receiptNumAndstockNum = receiptNum + "-" + stockNum;
            receiptNumAndstockNumList.add(receiptNumAndstockNum);
        }
        QueryWrapper<ProductTask> productTaskQueryWrapper = new QueryWrapper<>();
        for (String receiptNumAndstockNum : receiptNumAndstockNumList) {
            String[] receiptNumAndstockNumArray = receiptNumAndstockNum.split("-");
            productTaskQueryWrapper.eq("receipt_num", receiptNumAndstockNumArray[0]);
            productTaskQueryWrapper.eq("stock_num", receiptNumAndstockNumArray[1]);
            try {
                ProductTask productTask = productTaskMapper.selectOne(productTaskQueryWrapper);
                // 单据编号，备料料号不存在的时候，才能新增
                if (productTask == null) {
                    return productTaskService.insert(entity);
                } else {
                    return JsonResult.FAIL_EXCEPTION("该任务已存在,导入失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return JsonResult.FAIL_EXCEPTION("该任务已存在,导入失败");
            }
        }
        return JsonResult.OK("导入成功");
    }

    /**
     * 查询任务详情
     *
     * @param queryDto
     * @return
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @PostMapping("/getList")
    public Map getList(@RequestBody ProductTaskDTO queryDto) {
        return productTaskService.getList(queryDto);
    }

    /**
     * 工艺详情的插入
     *
     * @param technique
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.CODE_CREATE)
    // @BindPermission(name = OperationCons.CODE_CREATE, code = OperationCons.CODE_WRITE)
    @PostMapping("/insertTechnologyInfo")
    public JsonResult insert(@Valid @RequestBody Technique technique) throws Exception {
        return productTaskService.insertTechnologyInfo(technique);
    }

    /**
     * 更新对象后操作
     *
     * @param entityOrDto
     * @throws Exception
     */
    @Override
    protected void afterUpdated(ProductTask entityOrDto) throws Exception {
        uploadFileService.bindRelObjId(entityOrDto.getPrimaryKeyVal(), entityOrDto.getClass(), entityOrDto.getFileUuidList());
    }

    /**
     * 创建对象后操作
     *
     * @param entityOrDto
     * @throws Exception
     */
    @Override
    protected void afterCreated(ProductTask entityOrDto) throws Exception {
        uploadFileService.bindRelObjId(entityOrDto.getPrimaryKeyVal(), entityOrDto.getClass(), entityOrDto.getFileUuidList());
    }

    /**
     * 查询生产进度
     *
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @GetMapping("/getProductSchedule")
    public JsonResult getProductSchedule(ProductTaskDTO queryDto, Pagination pagination) throws Exception {
        return productTaskService.getProductSchedule(queryDto, pagination);
    }

    /**
     * 设备排产详情
     *
     * @param technique
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @GetMapping("/getPlanSchedule")
    public JsonResult getPlanSchedule(TechniqueDTO technique, Pagination pagination) throws Exception {
        List<Map<String, Object>> results = new ArrayList<>();
        List<ProductTask> listTask;
        List<Technique> listTechniques;
        int page = 1;
        int pagesize = 10;
        int totalCount;
        int totalPage;
        if (pagination != null) {
            page = pagination.getPageIndex();
            pagesize = pagination.getPageSize();
        }
        QueryWrapper<ProductTask> productTaskQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Technique> techniqueQueryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(technique.getTaskNum()) && !StringUtils.isEmpty(technique.getWorkEquipment())) {
            productTaskQueryWrapper.like("task_num", technique.getTaskNum());
            techniqueQueryWrapper.like("task_num", technique.getTaskNum());
            listTask = productTaskMapper.selectList(productTaskQueryWrapper);
            techniqueQueryWrapper.like("work_equipment", technique.getWorkEquipment());
            listTechniques = techniqueMapper.selectList(techniqueQueryWrapper);
        } else if (!StringUtils.isEmpty(technique.getWorkEquipment())) {
            techniqueQueryWrapper.like("work_equipment", technique.getWorkEquipment());
            listTechniques = techniqueMapper.selectList(techniqueQueryWrapper);
            listTask = productTaskMapper.selectList(productTaskQueryWrapper);
        } else if (!StringUtils.isEmpty(technique.getTaskNum())) {
            productTaskQueryWrapper.like("task_num", technique.getTaskNum());
            listTask = productTaskMapper.selectList(productTaskQueryWrapper);
            listTechniques = techniqueMapper.selectList(techniqueQueryWrapper);
        } else {
            listTask = productTaskMapper.selectList(productTaskQueryWrapper);
            listTechniques = techniqueMapper.selectList(techniqueQueryWrapper);
        }
        results = groupByField(mergeLists(listTask, listTechniques));
        sortByKey(results, "workEquipment");
        totalCount = results.size();
        if (results.size() % pagesize != 0) {
            totalPage = results.size() / pagesize + 1;
        } else {
            totalPage = results.size() / pagesize;
        }
        results = results.stream().skip((page - 1) * pagesize).limit(pagesize).collect(Collectors.toList());
        pagination.setTotalCount(totalCount);
        return JsonResult.OK(results).bindPagination(pagination);
    }

    /**
     * 根据任务单，拼接生产任务及工艺数据
     *
     * @param list1
     * @param list2
     * @return
     */
    protected List<Map<String, Object>> mergeLists(List<ProductTask> list1, List<Technique> list2) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (ProductTask item1 : list1) {
            Object commonValue = item1.getTaskNum();
            for (Technique item2 : list2) {
                if (item2.getTaskNum().equals(commonValue)) {
                    Map<String, Object> mergedItem = new HashMap<>();
                    mergedItem.put("workEquipment", item2.getWorkEquipment());
                    mergedItem.put("taskNum", item2.getTaskNum());
                    mergedItem.put("planNum", item1.getPlanNum());
                    mergedItem.put("profuctName", item1.getProductName());
                    mergedItem.put("productSpecification", item1.getProductSpecification());
                    mergedItem.put("techName", item2.getTechName());
                    mergedItem.put("techTime", item2.getTechTime());
                    mergedItem.put("quantity", item1.getQuantity());
                    if (item2.getOutput() == null) {
                        item2.setOutput((long) 0);
                    }
                    mergedItem.put("output", item2.getOutput());
                    mergedItem.put("surplusMin", (item1.getQuantity() - item2.getOutput()) * item2.getTechTime());
                    result.add(mergedItem);
                }
            }
        }
        return result;
    }

    /**
     * 统计相同设备的总的剩余工时
     *
     * @param jsonObjects
     * @return
     * @throws JsonProcessingException
     */
    public List<Map<String, Object>> groupByField(List<Map<String, Object>> jsonObjects) throws JsonProcessingException {
        List<Map<String, Object>> resultList = new ArrayList<>();
        resultList = jsonObjects;
        Map<String, Long> totalSurplusMin = new HashMap<>();
        for (Map<String, Object> map : jsonObjects) {
            String name = (String) map.get("workEquipment");
            long surplusMin = (long) map.get("surplusMin");
            if (totalSurplusMin.containsKey(name)) {
                totalSurplusMin.put(name, totalSurplusMin.get(name) + surplusMin);
            } else {
                totalSurplusMin.put(name, surplusMin);
            }
        }
        for (Map<String, Object> map : resultList) {
            map.put("totalSurplusMin", totalSurplusMin.get(map.get("workEquipment")));
        }
        return resultList;
    }

    /**
     * 排产数据以设备号进行排序
     *
     * @param data
     * @param key
     */
    public void sortByKey(List<Map<String, Object>> data, String key) {
        Collections.sort(data, new Comparator<Map<String, Object>>() {

            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                String value1 = (String) o1.get(key);
                String value2 = (String) o2.get(key);
                return value1.compareTo(value2);
            }
        });
    }

    /**
     * 根据任务单号查询该任务单下的所有物料
     *
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @GetMapping("/getGoods/{receiptNum}")
    public JsonResult getGoods(@PathVariable("receiptNum") String receiptNum) {
        return productTaskService.getGoods(receiptNum);
    }

    /**
     * 生产任务列表导出
     *
     * @param productTaskDTO
     * @return
     * @throws Exception
     */
    @Log(operation = "导出生产任务列表", businessObj = "ProductTask")
    // @BindPermission(name = OperationCons.LABEL_EXPORT, code = OperationCons.CODE_EXPORT)
    @GetMapping("/export")
    public JsonResult export(ProductTaskDTO productTaskDTO, @RequestParam(value = "columns", required = false) List<String> columns, HttpServletResponse response) throws Exception {
        QueryWrapper<ProductTask> queryWrapper = super.buildQueryWrapperByQueryParams(productTaskDTO);
        List<ProductTask> productTaskList = productTaskService.getViewObjectList(queryWrapper, null, ProductTask.class);
        if (V.isEmpty(productTaskList)) {
            return new JsonResult(Status.FAIL_OPERATION, "用户列表为空，导出失败");
        }
        String fileName = "生产任务列表导出_" + D.today() + ".xlsx";
        List<ProductTaskExportModel> dataList = this.entityList2ExcelList(productTaskList);
        ExcelHelper.exportExcel(response, fileName, ProductTaskExportModel.class, columns, dataList);
        return null;
    }

    /**
     * 实体列表转excel列表
     *
     * @param productTaskList
     * @return
     */
    private List<ProductTaskExportModel> entityList2ExcelList(List<ProductTask> productTaskList) {
        if (V.isEmpty(productTaskList)) {
            return Collections.emptyList();
        }
        List<ProductTaskExportModel> excelModelList = new ArrayList<>();
        for (ProductTask productTask : productTaskList) {
            ProductTaskExportModel excelModel = new ProductTaskExportModel();
            BeanUtils.copyProperties(productTask, excelModel);
            excelModelList.add(excelModel);
        }
        return excelModelList;
    }

    /**
     * 不带模糊查询的list接口
     *
     * @return
     * @throws Exception
     */
    @Log(operation = OperationCons.LABEL_LIST)
    // @BindPermission(name = OperationCons.LABEL_LIST, code = OperationCons.CODE_READ)
    @GetMapping("/getProductTaskByReceiptNum")
    public JsonResult getProductTaskByReceiptNum(@RequestParam("receiptNum") String receiptNum) throws Exception {
        QueryWrapper<ProductTask> wrapper = new QueryWrapper<>();
        wrapper.eq("receipt_num", receiptNum);
        List<ProductTask> productTaskList = productTaskMapper.selectList(wrapper);
        return JsonResult.OK(productTaskList);
    }
}
